home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / contrib / 3M / pg_exec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  10.7 KB  |  388 lines

  1. #include "tmp/libpq.h"
  2. #include <stdio.h>
  3.  
  4. #define LL 1000        /* upper limit on length of a data line */
  5. #define VPL '{'        /* left hand side of a var in template */
  6. #define VPR '}'         /* right hand side of var in template */ 
  7. #define MAX_COL 99      /* max number of columns per data line 
  8.                            if MAX_COL is larger than 99, fix code in 
  9.                            pg_process_data_file to handle more than 2 digits */ 
  10. #define NULL_CHAR '&'
  11.  
  12.  
  13. /**********************************************************************
  14.   $Header: /private/postgres/src/contrib/3M/RCS/pg_exec.c,v 1.3 1991/05/15 08:37:17 mao Exp $
  15.  **********************************************************************
  16.  FILE: pg_exec.c
  17.        pg_exec [-c | -d] databasename filename
  18.  
  19.        Author:  Steve Anastasi, 3M, 612-733-6970
  20.                 smanastasi@mmm.serc.3m.com
  21.  
  22.        
  23.  
  24.        Date: 6-29-90
  25.  
  26.        Processes ascii files as postgres commands.  This program takes
  27.        a two arguments - a database name, and a filename or pathname
  28.        of an ascii file.  The database must already exist.
  29.        Two options are available:
  30.  
  31.          -c  Process the ascii file as a sequence of postgres
  32.          commands.  This is the default.  See the format of a
  33.          postgres command file below.
  34.  
  35.          -d  Process the ascii file as data file.  Data in the file is
  36.          imported according to a specification contained on the
  37.          first line of the file.  See the format of a import file
  38.          below. 
  39.  
  40.        Command file format:
  41.        --------------------
  42.        Each line is simply a postgres command that can be executed
  43.        directly using PQexec.  Using pg_exec -c <filename> has the
  44.        same effect as using the terminal monitor interface and
  45.        including the filename (\i filename).  
  46.  
  47.        It is important that each postgres command is entirely
  48.        contained on a single line and the each line is deliminated by
  49.        a newline or return character.
  50.  
  51.        Import file format:
  52.        -------------------
  53.        An import file is composed of two sections.  The first section
  54.        is the first line of the file.  It specifies the postgres
  55.        command that should be used to add the data to the database.
  56.        This is called the command template.
  57.  
  58.        The second section is the rest of the file.  Each line is a
  59.        tab-deliminated record containing data.  Special tokens ({num})
  60.        in the command template specify the column of data that should be
  61.        used.  An example follows.
  62.  
  63.        append somerel (name={0}::text, id={1}, gpa={2}::float4)
  64.        "David Byrne"  154323  "3.00"
  65.        "Phillip E. Bach"      000321  "3.93"
  66.        "Ronald Reagan"        000000  "0.00"
  67.        "Cole Porter"  103423  "2.45"
  68.  
  69.        Note that each field is tab-delimited and each value must be in
  70.        the proper syntax so it can be dropped right in for its {#}.
  71.  
  72.        In addition, no null values can be specified in a dataline by
  73.        \tab\tab or any other trick.  For example, if {7} is the
  74.        largest number (7) in the command template, then there must be
  75.        8 values (0,1,2,...,7) on every line of data.
  76. */
  77.  
  78.  
  79. /**********************************************************************
  80.    pqexec_ret
  81.  
  82.    Looks at first character of the string returned by pqexec.  If
  83.    there is an error, -1 is returned, else 1 is returned.
  84.    */
  85. int pqexec_ret (s)
  86.   char *s;
  87. {
  88.   if (s[0] == 'R')
  89.     return(-1);
  90.   else
  91.     return(1);
  92. }
  93.  
  94.  
  95.  
  96.  
  97.  
  98. /**********************************************************************
  99.    Read a text string from an ascii file.  A text string is defined as
  100.    text deliminated by either a tab, newline or return character.
  101.    In the process of reading a string, the file pointer gets advanced.
  102.    Note that spaces do not deliminate strings.
  103.    */
  104.  
  105. void get_string(fptr, string_buffer)
  106.   FILE *fptr;
  107.   char *string_buffer;
  108. {
  109.   int i;
  110.  
  111.   i = 0;
  112.   if ((string_buffer[i] = getc(fptr)) != EOF) {
  113.     while (string_buffer[i] != EOF &&
  114.            string_buffer[i] != '\t' &&
  115.            string_buffer[i] != '\n' &&
  116.            string_buffer[i] != '\r') {
  117.       i = i+1;
  118.       string_buffer[i] = getc(fptr);
  119.     }
  120.   }    
  121.   /* Now replace the last character with a null terminater */
  122.   string_buffer[i] = '\0';
  123.  
  124.  
  125. /**********************************************************************
  126.    Read a line from a text file.  A line is defined as any character
  127.    string that ends in \n .  Returns a ptr to a null terminated string
  128.  
  129.    NOT CURRENTLY USED.  USE GET_STRING INSTEAD IF POSSIBLE
  130.    */
  131.    
  132. char * readline(fptr)
  133.   FILE *fptr;
  134. {
  135.   char buffer[LL];
  136.   int i;
  137.  
  138.   i = 0;
  139.   buffer[i] = getc(fptr);
  140.   while (buffer[i] != EOF && buffer[i] != '\n')
  141.     buffer[++i] = getc(fptr);
  142.   buffer[i] = '\0';
  143.   return(buffer);
  144. }
  145.  
  146.   
  147. /*********************************************************************
  148.    pg_process_data_file 
  149.  
  150.    Reads formatted data from a ascii file and inserts the data into
  151.    a postgres relation.  One file can contain data for only one
  152.    relation.  
  153.  
  154.    File Format:
  155.    The first line is a template to be used to specify how the data
  156.    will get append to a relation.  The token VPL and VPR  indicates a place
  157.    to drop in data from the data file.  In each VP is a number
  158.    indicating what field from a data line to use.  (See top of file
  159.    for definition of VPL and VPR.)
  160.  
  161.    Example:
  162.    A datafile might look like:
  163.  
  164.    append parameter (name={0}::text, age={1}, weight={2}::float4)
  165.    Steve Anastasi     26     190.04
  166.    Saavik Stargazer     1     67.30
  167.    etc.,
  168.  
  169.    Note that each field is tab delimited and each line ends in a newline
  170.    or return character.
  171.  
  172.    Limitations:  At most, MAX_COL data columns can be handled
  173.                  Every column in the data file must have a value 
  174.    */
  175.  
  176.  
  177. void pg_process_data_file(fptr)
  178.   FILE *fptr;
  179.  
  180. {
  181.   char header[LL], command_string[LL*2], data[LL], tc;
  182.   char var_num[3], tk[MAX_COL][LL];
  183.   int i, h_ctr, c_ctr, token_count, var_val, EOF_REACHED;
  184.  
  185.   EOF_REACHED = 0;
  186.   get_string(fptr, header);
  187.   /* Find out how many data fields should be on each data line.  This
  188.      is done by finding the maximum number enclosed in VPL and VPR. 
  189.      The number of data fields is this number plus 1 (since counting
  190.      starts at 0. */
  191.   token_count = 0;
  192.   i = 0;
  193.   while (header[i] != '\0')  {
  194.     if (header[i] == VPL) {
  195.       /* see if there is one or two digits after VPL */
  196.       if (header[i+2] == VPR) {  /* one digit */
  197.         var_num[0] = '0';
  198.         var_num[1] = header[i+1];
  199.         var_num[2] = '\0';
  200.       }
  201.       else if (header[i+3] == VPR) { /* 2 digits */
  202.         var_num[0] = header[i+1];
  203.         var_num[1] = header[i+2];
  204.         var_num[2] = '\0';
  205.       }
  206.       else { /* problem */
  207.         printf("Error in data file.  Unknown {  } syntax\n");
  208.         abort();
  209.       }
  210.       sscanf(var_num, "%d", &var_val);
  211.       if (var_val > token_count)
  212.         token_count = var_val;
  213.     }
  214.     i = i+1;
  215.   }
  216.  
  217.   /* Iterate thru all data lines */
  218.   while (!EOF_REACHED) {
  219.     /* Now get as many strings from the data file as specified by
  220.        token count */
  221.     for (i=0;i<=token_count;i++) {
  222.       get_string(fptr, tk[i]);
  223.       if (tk[i][0] == '\0') 
  224.     EOF_REACHED = 1;
  225.     }
  226.  
  227.     /* Now start to copy header into command_string, and replace
  228.        {x} with tk[x] */
  229.     h_ctr = 0;
  230.     c_ctr = 0;
  231.     while (header[h_ctr] != '\0' && c_ctr < LL*2 && !EOF_REACHED) {
  232.       /* printf("H[%d]: %c\nC: %s\n",h_ctr,header[h_ctr],command_string); */
  233.       if (header[h_ctr] == VPL) {
  234.         /* see if there is one or two digits after VPL */
  235.         if (header[h_ctr+2] == VPR) {  /* one digit */
  236.           var_num[0] = '0';
  237.           var_num[1] = header[h_ctr+1];
  238.           var_num[2] = '\0';
  239.           h_ctr = h_ctr + 3;  /* advance to after VPR */
  240.         }
  241.         else if (header[h_ctr+3] == VPR) { /* 2 digits */
  242.           var_num[0] = header[h_ctr+1];
  243.           var_num[1] = header[h_ctr+2];
  244.           var_num[2] = '\0';
  245.           h_ctr = h_ctr + 4;  /* advance to after VPR */
  246.         }
  247.         else { /* problem */
  248.           printf("Error in data file.  Unknown {  } syntax\n");
  249.           abort();
  250.         }
  251.         sscanf(var_num, "%d", &var_val);
  252.   
  253.       /* now splice in tk[var_val] to command_string */
  254.         i = 0;
  255.         while (*(tk[var_val]+i) != '\0') {
  256.           command_string[c_ctr] = *(tk[var_val]+i);
  257.           i = i+1;
  258.           c_ctr = c_ctr+1;
  259.         }
  260.       } /* header[h_ctr] == VPL */
  261.       else { /* just copy from header to command string */
  262.         command_string[c_ctr] = header[h_ctr];
  263.         h_ctr = h_ctr + 1;
  264.         c_ctr = c_ctr + 1;
  265.       }
  266.     }
  267.     if (!EOF_REACHED) {
  268.       /* Now execute the query */
  269.       command_string[c_ctr] = '\0';
  270.       printf("Exec: %s\n", command_string); 
  271.       if (pqexec_ret(PQexec(command_string)) < 0)
  272.         printf("*Error* %s\n", command_string);
  273.     }
  274.   } /* end while not EOF_REACHED */
  275.   printf("\n");
  276. }    
  277.   
  278.  
  279. /*******************************************************************
  280.   pg_process_command_file
  281.  
  282.   Reads a ascii file of postgres commands and executes them.  Each
  283.   command must be on a single line.
  284.   */
  285.  
  286. void pg_process_command_file(fptr)
  287.   FILE *fptr;
  288.  
  289. {
  290.   char command[255];
  291.   int EOF_REACHED;
  292.  
  293.   EOF_REACHED = 0;
  294.  
  295.   while (!EOF_REACHED) {
  296.     get_string(fptr, command);
  297.     if (command[0] == '\0') 
  298.       EOF_REACHED = 1;
  299.     else {
  300.       printf("Exec: %s\n", command); 
  301.       if (pqexec_ret(PQexec(command)) < 0)
  302.         printf("*Error* %s\n", command);
  303.     }
  304.   }
  305.   printf("\n");
  306. }
  307.  
  308.   
  309.   
  310. /******************************************************************* */
  311. main (argc, argv)
  312.   int argc;
  313.   char *argv[];
  314.  
  315. {
  316.   FILE *fopen(), *fptr;
  317.   char db_name[16],filename[80], *s, option;
  318.   int place, j, error;  /* error: -1= bad command line, -2=bad file, -3=bad */
  319.          /* db name */
  320.  
  321.   error = 0;
  322.   /* check for bad command line */
  323.   if (argc < 3)
  324.     error = -1;
  325.   else if (argc==3 && (argv[1][0] == '-' || argv[2][0] == '-'))
  326.     error = -1;
  327.   else if (argc==4 && (argv[1][0] != '-' || argv[2][0] == '-' ||
  328.               argv[3][0] == '-'))
  329.     error = -1;
  330.   else if (argc > 4)
  331.     error = -1;
  332.  
  333.   if (error == -1) {
  334.     printf("Usage: pg_exec [-c | -d] dbname filename\n");
  335.     exit(-1);
  336.   }
  337.  
  338.   /* get the option */
  339.   if (argv[1][0] == '-')
  340.     option = argv[1][1];
  341.   else
  342.     option = 'c';   /* the default */
  343.  
  344.   /* get the database */
  345.   if (argv[1][0] == '-')
  346.     place = 2;
  347.   else
  348.     place = 1;
  349.  
  350.   j = 0;
  351.   while (argv[place][j] != '\0' && j < 16) {
  352.  
  353.     db_name[j] = argv[place][j];
  354.     j = j + 1;
  355.   }
  356.  
  357.   j =0;
  358.   /* get file name */
  359.   place = place +1;
  360.   while (argv[place][j] != '\0' && j < 80) {
  361.     filename[j] = argv[place][j];
  362.     j = j + 1;
  363.   }
  364.  
  365.   
  366.   /* Now do the right thing */
  367.  
  368.   PQsetdb(db_name); 
  369.  
  370.   printf("*Database: %s\n", PQdb());
  371.  
  372.   fptr = fopen(filename, "r");;
  373.   if (fptr == (FILE *) NULL) {
  374.     printf("Had problem opening %s.\n", filename);
  375.     exit(-1);
  376.   }
  377.  
  378.   if (option == 'c')
  379.     pg_process_command_file(fptr);
  380.   else if (option == 'd')
  381.     pg_process_data_file(fptr);
  382.  
  383.   close (fptr);
  384. }
  385.  
  386.  
  387.